/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package net.worlds.object;

import java.awt.Color;
import java.awt.Graphics;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import net.worlds.WorldsException;
import net.worlds.Main;
import org.jbox2d.collision.shapes.CircleDef;
import org.jbox2d.collision.MassData;
import org.jbox2d.collision.shapes.Shape;
import org.jbox2d.common.Vec2D;
import org.jbox2d.dynamics.Body;
import org.jbox2d.dynamics.BodyDef;
import org.jbox2d.dynamics.joints.DistanceJointDef;
import org.jbox2d.dynamics.joints.RevoluteJoint;
import org.jbox2d.dynamics.joints.RevoluteJointDef;


public class Rope extends Joint{
    private float segmentLength = 2;
    protected Vec2D anchor1;
    protected Vec2D anchor2;
    private RevoluteJoint joint1;
    private RevoluteJoint joint2;
    private LinkedHashMap<Body, Shape> segments;
    private ArrayList<org.jbox2d.dynamics.joints.Joint> joints;
    private boolean created = false;
    public Rope() throws WorldsException
    {
        super("Rope");
    }
    public Vec2D getAnchor1()
    {
        if(joint1 == null)
            return Vec2D.ORIGIN;
        else
            return new Vec2D(joint1.getAnchor1());
    }
    public Vec2D getAnchor2()
    {
        if(joint2 == null)
            return Vec2D.ORIGIN;
        else
            return new Vec2D(joint2.getAnchor1());
    }
    @Override
    protected void createJoint() throws WorldsException {
        anchor1 = getVec2DProp("Anchor1");
        anchor2 = getVec2DProp("Anchor2");
        Vec2D distance = anchor2.sub(anchor1);
        int numSegments = 10;
        segmentLength = (float) (distance.length() / numSegments);
        segments = new LinkedHashMap<Body, Shape>(numSegments);
        joints = new ArrayList<org.jbox2d.dynamics.joints.Joint>(numSegments - 1);
        Body lastBody = null;
        if(!(part1 instanceof Circle))
            part1.getBody().m_angularDamping = 0.5f;
        if(!(part2 instanceof Circle))
            part2.getBody().m_angularDamping = 0.5f;
        for(int i = 0; i < numSegments; i++)
        {
            CircleDef sd = new CircleDef();
            sd.radius = segmentLength / 2;
            float r = (float)i/numSegments;
            sd.density = 0.5f;
            sd.friction = 0.5f;
            BodyDef bd = new BodyDef();
            bd.position = anchor1.add(distance.mul(r));
            Body b = world.addBody(bd);
            Shape shape = b.createShape(sd);

            shape.isRope = true;
            b.setMassFromShapes();
            MassData md = new MassData();
            md.center = new Vec2D(0, 0);
            md.mass = (part1.getBody().getMass() + part2.getBody().getMass()) / numSegments / 5;
            if(part1.getBody().getMass() == 0 || part2.getBody().getMass() == 0)
                md.mass *= 2;
            md.I = md.mass * (0.5f * sd.radius * sd.radius + Vec2D.dot(sd.localPosition, sd.localPosition));
            b.setMass(md);
            b.m_angularDamping = 2;
            b.m_linearDamping = 1;
            if(lastBody != null)
            {
                DistanceJointDef def = new DistanceJointDef();
                def.initialize(b, lastBody, b.getPosition(), lastBody.getPosition());
                def.frequencyHz = 10;
                def.dampingRatio = 40;
                joints.add(world.addJoint(def));
            }
            if(i == numSegments - 1 && part2 != null)
            {
                RevoluteJointDef def = new RevoluteJointDef();
                def.body1 = b;
                def.body2 = part2.getBody();
                def.localAnchor1 = b.getLocalPoint(anchor2);
                def.localAnchor2 = part2.getBody().getLocalPoint(anchor2);
                def.enableMotor = true;
                def.maxMotorTorque = 5000;
                joint2 = (RevoluteJoint) world.addJoint(def);
                joint2.enableMotor(true);
                joint2.setMaxMotorTorque(5000);
                joints.add(joint2);
            }
            else if(i == 0 && part1 != null)
            {
                RevoluteJointDef def = new RevoluteJointDef();
                def.body1 = b;
                def.body2 = part1.getBody();
                def.localAnchor1 = b.getLocalPoint(anchor1);
                def.localAnchor2 = part1.getBody().getLocalPoint(anchor1);
                joint1 = (RevoluteJoint)world.addJoint(def);
                joint1.enableMotor(true);
                joint1.setMaxMotorTorque(5000);
                joints.add(joint1);
            }
            segments.put(b, shape);
            lastBody = b;
        }
        created = true;
    }

    @Override
    public void destructor() throws WorldsException
    {
        super.destructor();
        if(!(part1 instanceof Circle))
            part1.getBody().m_angularDamping = 0.0f;
        if(!(part2 instanceof Circle))
            part2.getBody().m_angularDamping = 0.0f;
        for(org.jbox2d.dynamics.joints.Joint j : joints)
        {
            world.destroyJoint(j);
        }
        for(Body b : segments.keySet())
        {
            b.destroyShape(segments.get(b));
            world.removeBody(b);
        }
    }

    public void draw(Graphics g) throws WorldsException
    {
        if(!created || disabled || part1 == null || part2 == null || part1.disabled || part2.disabled)
            return;
        Vec2D oldPosition = null;
        int i = 0;
        for(org.jbox2d.dynamics.joints.Joint j : joints)
        {
            Vec2D position = new Vec2D(j.getAnchor1()).worldToScreen(Main.getView());
            Color c = getColorProp("Color");
            if(oldPosition != null && getBooleanProp("Visible"))
            {
                g.setColor(c);
                g.drawLine((int) oldPosition.x, (int) oldPosition.y, (int) position.x, (int) position.y);
            }
            oldPosition = position;
            if(Main.canUseTools && (i == 0 || i == joints.size() - 1))
            {
                g.setColor(new Color(c.getRed(), c.getGreen(), c.getBlue(), 127));
                g.fillOval((int) position.x - 4, (int) position.y - 4, 8, 8);
                if(selected)
                {
                    g.setColor(Color.white);
                    g.drawOval((int) position.x - 4, (int) position.y - 4, 8, 8);
                }
            }
            i++;
        }
    }
}
